/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prognosisdataalgo.fuzzy;

import prognosisdataalgo.Coordinate;
import prognosisdataalgo.PrognosisFunction;
import prognosisdataalgo.comparators.MaxMinComparator;

import java.util.*;

/**
 * @author ApT
 */
public class FuzzyCorrectify extends PrognosisFunction implements FuzzyRules {

    private Map<String, String> databaseRule = new HashMap<String, String>();
    private double[] distanceValues = new double[]{0, 0, 0};
    private double[] negativeFactorsDistance = new double[]{0, 0, 0};
    private final double[] valuesCoordinate = new double[]{0, 45, 90};
    private final double[] valuesResult = new double[]{20, 55, 90};
    private final Map<String, Double> valuesDatabase = new HashMap<String, Double>();
    private final String[] fuzzyValues = new String[]{"l", "m", "h"};
    private boolean isCar = false;
    /*
     * Coordinate values
     */
    private Coordinate baseCoordinate;
    private List<Coordinate> positiveCoordinates;
    private List<Coordinate> negativeCoordinates;

    public FuzzyCorrectify(Coordinate baseCoordinate, List<Coordinate> positiveCoordinates, List<Coordinate> negativeCoordinates, boolean isCar) {
        this.baseCoordinate = baseCoordinate;
        this.positiveCoordinates = positiveCoordinates;
        this.negativeCoordinates = negativeCoordinates;
        this.isCar = isCar;

        initializeDatabaseRules();

        initializeDistance();
        initializeFactorsDistance();
        initializeCoordinateValueFuzzy();

        calculateFuzzyCorrectifyFactors();
    }

    private void initializeDatabaseRules() {

        for (int i = 0; i < valuesResult.length; i++) {
            valuesDatabase.put(fuzzyValues[i], valuesResult[i]);
        }
        if (!isCar) {
            for (int i = 0; i < rulesBase.length; i++) {
                databaseRule.put(rulesBase[i], resultBase[i]);
            }
        } else {
            for (int i = 0; i < rulesBase.length; i++) {
                databaseRule.put(rulesBase[i], carResultBase[i]);
            }
        }
    }

    private void initializeDistance() {
        List<Double> valuesList = new ArrayList<Double>();
        for (Coordinate coordinate : positiveCoordinates) {
            double distanceBetwen = distance(coordinate.getCoordinate(), baseCoordinate.getCoordinate());
            valuesList.add(distanceBetwen);
            coordinate.setDistanceValueFuzzy(distanceBetwen);
        }
        Collections.sort(valuesList, new MaxMinComparator());
        distanceValues[0] = valuesList.get(0);
        distanceValues[2] = valuesList.get(valuesList.size() - 1);
        distanceValues[1] = (valuesList.get(0) + valuesList.get(valuesList.size() - 1)) / 2;

        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setDistanceFuzzy(getFuzzyFactors(distanceValues, coordinate.getDistanceValueFuzzy()));
        }
    }

    private void initializeFactorsDistance() {
        List<Double> valuesList = new ArrayList<Double>();
        for (Coordinate c : positiveCoordinates) {
            double value = 0;
            for (Coordinate c1 : negativeCoordinates) {
                value += distance(c.getCoordinate(), c1.getCoordinate());
            }
            valuesList.add(value);
            c.setNegativeFactorsDistanceValueFuzzy(value);
        }
        Collections.sort(valuesList);

        negativeFactorsDistance[0] = valuesList.get(0);
        negativeFactorsDistance[2] = valuesList.get(valuesList.size() - 1);
        negativeFactorsDistance[1] = (valuesList.get(0) + valuesList.get(valuesList.size() - 1)) / 2;

        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setNegativeFactorsFuzzy(getFuzzyFactors(negativeFactorsDistance, coordinate.getNegativeFactorsDistanceValueFuzzy()));
        }
    }

    private void initializeCoordinateValueFuzzy() {
        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setValuesFuzzy(getFuzzyFactors(valuesCoordinate, (coordinate.getValue()
                    + coordinate.getDayFactorValue())));
        }
    }

    private void calculateFuzzyCorrectifyFactors() {
        for (Coordinate coordinate : positiveCoordinates) {
            coordinate.setResultFuzzy(databaseRule.get(coordinate.compileFuzzyFactors()));
            coordinate.setFuzzyCorrectifyValue(valuesDatabase.get(coordinate.getResultFuzzy()));
        }
    }

    private String getFuzzyFactors(double[] minMaxValues, double value) {
        for (int i = 0; i < minMaxValues.length - 1; i++) {
            if ((value >= minMaxValues[i]) && (value < minMaxValues[i + 1])) {
                return fuzzyValues[i];
            }
        }
        return fuzzyValues[fuzzyValues.length - 1];
    }
}
